/**
 * This class is originally from BioTransformer and then be  modified.
 * @author of BioTransformer is Djoumbou Feunang, Yannick, PhD
 *
 */

package wishartlab.cfmid_plus.molecules;

import java.util.ArrayList;

import org.openscience.cdk.CDKConstants;
import org.openscience.cdk.aromaticity.Aromaticity;
import org.openscience.cdk.aromaticity.ElectronDonation;
import org.openscience.cdk.aromaticity.Kekulization;
import org.openscience.cdk.exception.CDKException;
import org.openscience.cdk.graph.Cycles;
import org.openscience.cdk.interfaces.IAtomContainer;
import org.openscience.cdk.interfaces.IBond;
import org.openscience.cdk.interfaces.IChemObjectBuilder;
import org.openscience.cdk.isomorphism.Pattern;
import org.openscience.cdk.layout.StructureDiagramGenerator;
import org.openscience.cdk.silent.SilentChemObjectBuilder;
import org.openscience.cdk.smiles.smarts.SmartsPattern;
import org.openscience.cdk.tools.CDKHydrogenAdder;
import org.openscience.cdk.tools.manipulator.AtomContainerManipulator;
import ambit2.smarts.SMIRKSManager;
import ambit2.smarts.SMIRKSReaction;

public class ChemStructureManipulator {
	protected static SMIRKSManager smrkMan = new SMIRKSManager(SilentChemObjectBuilder.getInstance());
//	protected static StructureStandardizer sstandardizer = new ambit2.tautomers.processor.StructureStandardizer();
	
	public ChemStructureManipulator() {
		// TODO Auto-generated constructor stub
		smrkMan.setFlagApplyStereoTransformation(false);
		smrkMan.setFlagCheckResultStereo(true);
		smrkMan.setFlagFilterEquivalentMappings(true);
		smrkMan.setFlagProcessResultStructures(true);
		smrkMan.setFlagAddImplicitHAtomsOnResultProcess(true);
		
//		sstandardizer.setEnabled(true);
//		sstandardizer.setImplicitHydrogens(true);
//		sstandardizer.setGenerate2D(true);
//		sstandardizer.setNeutralise(false);
////		sstandardizer.setGenerateStereofrom2D(true);
//		sstandardizer.setGenerateSMILES(true);	
//		sstandardizer.setGenerateTautomers(true);
	}
	
	/**
	 * This function applies some preprocessing operations, such as setting the
	 * flag of atoms from aromatic rings to "ISAROMATIC", and kelulizing
	 * molecules.
	 * 
	 * @param molecule
	 *            : A molecule of interest
	 * @return : A processed molecule (AtomContainer)
	 * @throws Exception 
	 */
//	public static IAtomContainer preprocessContainer(IAtomContainer molecule)
//			throws Exception {
//
//		IAtomContainer molClone =  molecule.clone();
//
//		return sstandardizer.process(molClone);	
//	}
	
	public static IAtomContainer preprocessContainer(IAtomContainer molecule)
			throws CDKException {
		
		AtomContainerManipulator.percieveAtomTypesAndConfigureAtoms(molecule);
//		AtomContainerManipulator.convertImplicitToExplicitHydrogens(molecule);
		
//	    Aromaticity aromaticity = new Aromaticity( ElectronDonation.cdk(), Cycles.cdkAromaticSet());
		Aromaticity aromaticity = new Aromaticity(ElectronDonation.daylight(), Cycles.or(Cycles.all(), Cycles.all(6)));
		
		for (IBond bond : molecule.bonds()) {
			if (bond.isAromatic() && bond.getOrder() == IBond.Order.UNSET) {
				bond.setFlag(CDKConstants.ISAROMATIC, true);
				bond.getAtom(0).setFlag(CDKConstants.ISAROMATIC, true);
				bond.getAtom(1).setFlag(CDKConstants.ISAROMATIC, true);

			} 
		}
		aromaticity.apply(molecule);
		StructureDiagramGenerator sdg = new StructureDiagramGenerator();
		sdg.setMolecule(molecule);
		sdg.generateCoordinates();		
		IAtomContainer layedOutMol = sdg.getMolecule();


		return layedOutMol;
	}
	public static IAtomContainer standardizeMoleculeWithCopy(IAtomContainer molecule, boolean preprocess) throws Exception{
		CDKHydrogenAdder adder = CDKHydrogenAdder.getInstance(SilentChemObjectBuilder.getInstance());
		IAtomContainer molClone =  molecule.clone();
		IChemObjectBuilder bldr = SilentChemObjectBuilder.getInstance();
		if(preprocess){
			molClone = ChemStructureManipulator.preprocessContainer(molClone);
			AtomContainerManipulator.convertImplicitToExplicitHydrogens(molClone);
		} else {
			AtomContainerManipulator.percieveAtomTypesAndConfigureAtoms(molClone);
			AtomContainerManipulator.convertImplicitToExplicitHydrogens(molClone);
		}
		ArrayList<ReactionObject> reactionList = StandardizationRules.standardizationReactions;
		for(int i = 0; i < reactionList.size(); i++){
			ReactionObject oneReaction = reactionList.get(i);
			String reactantSMIRKS = oneReaction.getReactantSMIRKS();
			Pattern smp = SmartsPattern.create(oneReaction.getReactantSMIRKS(), bldr);				
			boolean matchedPatter = smp.matches(molecule);
			if(matchedPatter){
				SMIRKSReaction sReaction = smrkMan.parse(oneReaction.getReactionSMIRKS());
				smrkMan.applyTransformation(molClone, sReaction);
				AtomContainerManipulator.percieveAtomTypesAndConfigureAtoms(molClone);	
				adder.addImplicitHydrogens(molClone);
			}
		}
		AtomContainerManipulator.suppressHydrogens(molClone);
		return molClone;
	}

	
	

}
